using System.Collections;
using System.Linq;
using UnityEngine;
using UnityEngine.SceneManagement;

public class GameManager : MonoBehaviour, ISaveable
{
    public static GameManager Instance;

    private Vector3 lastPlayerPosition;
    private string lastScenePlayed;
    private bool isLoadDataOver;
    private void Awake()
    {
        if (Instance != null && Instance != this)
        {
            Destroy(gameObject);
            return;
        }
        Instance = this;
        DontDestroyOnLoad(gameObject);
    }

    public void StartGame()
    {
        LoadScene(lastScenePlayed);
    }
    public void ReStartGame()
    {
        //重新加载当前游戏场景
        string sceneName = SceneManager.GetActiveScene().name;
        LoadScene(sceneName);
    }
    public void LoadScene(string sceneName, RespawnType connectedWayPoint = RespawnType.None)
    {
        SaveManager.Instance.SaveGame();
        StartCoroutine(SceneChangeCo(sceneName, connectedWayPoint));
    }

    private IEnumerator SceneChangeCo(string sceneName, RespawnType respawnType)
    {
        UI_FadeEffect fadeEffect = GetFadeEffectUI();
        fadeEffect?.DoFadeIn();

        yield return fadeEffect?.fadeEffectCo;

        SceneManager.LoadScene(sceneName);
        
        isLoadDataOver = false;
        yield return null;

        while (isLoadDataOver == false)
            yield return null;

        fadeEffect = GetFadeEffectUI();
        fadeEffect?.DoFadeOut(1);

        Player player = Player.Instance;
        if (player == null)
            yield break;

        Vector3 position = GetNewPlayerSpawnPosition(respawnType);

        if (position != Vector3.zero)
            Player.Instance.SetTeleportPosition(position);
    }

    private UI_FadeEffect GetFadeEffectUI() => FindObjectOfType<UI_FadeEffect>();
    private Vector3 GetNewPlayerSpawnPosition(RespawnType type)
    {
        if (type != RespawnType.None)
            return GetPlayerSpawnPosition(type);

        Object_WayPoint[] wayPoints = FindObjectsByType<Object_WayPoint>(FindObjectsSortMode.None);
        Object_CheckPoint[] checkPoints = FindObjectsByType<Object_CheckPoint>(FindObjectsSortMode.None);

        Vector3[] enterPositions = wayPoints
                                ?.Where(target => target.GetWayPointType() == RespawnType.Enter)
                                ?.Select(target => target.GetPositionAndSetTrigger())
                                ?.ToArray();
        Debug.Log(SaveManager.Instance.GetGameData());
        Vector3[] triggeredCheckPosition = checkPoints
                                        ?.Where(target => SaveManager.Instance.GetGameData().checkPoint.TryGetValue(target.GetCheckPointId(), out bool isActive) && isActive)
                                        ?.Select(target => target.GetCheckPointPosition())
                                        ?.ToArray();

        Vector3[] targetPosition = enterPositions.Concat(triggeredCheckPosition).ToArray();

        if (targetPosition.Length == 0)
            return Vector3.zero;

        return targetPosition.OrderBy(target => Vector3.Distance(lastPlayerPosition, target)).First();
    }

    private Vector3 GetPlayerSpawnPosition(RespawnType type)
    {
        var wayPoints = FindObjectsByType<Object_WayPoint>(FindObjectsSortMode.None);

        foreach (var point in wayPoints)
        {
            if (point.GetWayPointType() == type)
                return point.GetPositionAndSetTrigger();

        }
        return Vector3.zero;
    }

    public void SaveData(ref GameData gameData)
    {
        string currentScene = SceneManager.GetActiveScene().name;
        if (currentScene == "Main Menu")
            return;
        gameData.lastPlayerPosition = Player.Instance.transform.position;
        gameData.lastScenePlayed = currentScene;
    }

    public void LoadData(GameData gameData)
    {
        lastScenePlayed = gameData.lastScenePlayed;
        lastPlayerPosition = gameData.lastPlayerPosition;
        if (string.IsNullOrEmpty(lastScenePlayed))
            lastScenePlayed = "Level_0";
        isLoadDataOver = true;
    }
}
